
	/***********************************************************************************************

		@API
		Class: 		DataSet
		Inherits:	jsl.OptionMap, jsl.EventMap

		Static:
			ds		setFilter			(id, filter)
			ds		setOrder			(id, order)
			ds		setFunction		(id, f)

		Constructor:
			ds		DataSet				(ds/metadata, options*)

		Info:
			t			type					()
			c			connector			()
			md		metadata			(column*)
			n			count					(pages*)

		Definitions:
			ds		setFilter			(id, filter)
			ds		setOrder			(id, order)
			ds		setFunction		(id, f)

		Transformations:
			s			toString			(format*, options*)
			a			toArray				(objects*)
			n			valueOf				()

		Operations:
			rs	  read					(n/field*, old*)
			ds		update				(field/rows, value*)
			ds		insert				(n/rows*)
			ds		append				(n/rows*)
			ds		remove				(n*)
			ds		clear					(rule*)

			ds		filter				(filter*, params*..)
			ds		sort					(order, 	params*..)
			v			execute				(f, 			params*..)

      ds    inject        (data, options*)
      rs    rows          (filter/i1*, i2*)
      col   column        (id, filter*)
			ds   	walk					(action)

		Commands:
			ds		refresh				()
			ds		commit				()
			ds		revert				()

		Seek:
			ds		top						()
			ds		end						()

			ix		index					(ix*)
			ds		next					(n*)
			ds		prev					(n*)

			pg		page					(ix*)
			ds		nextPage			(n*)
			ds		prevPage			(n*)

		Options:
			readonly, pagesize, refresh, autocommit

		Events:
			beforeRead, 		beforeChange, 	beforeUpdate		beforeInsert,	beforeRemove, beforeClear,    beforeFilter, beforeSort,
			beforeInject,		beforeExecute, 	beforeRefresh, 	beforeCommit, beforeRevert

			read, 					change, 				update,				insert, 				remove, 			clear, 				filter, 			sort,
			inject,					execute, 				refresh,			commit, 				revert

		Note:
			ds types:						memory(d), net, db
			ds metadata:				[ { id, type, value, key }, .. ]
			ds g.functions:			max, min, avg, sum

	************************************************************************************************/

	//-------------------------------------------------------------------------------
	jsl.Class("jsl.DataSource.DataSet", {

		//-------------------------------------------------------------------------------
		inherits: [ jsl.OptionMap, jsl.EventMap ],

		//-------------------------------------------------------------------------------
		initializer: function() {
			var p

			//global predefined functions
			//----------------------------------------------
			this.setFunction("min", function(column) {
				var v, t, c, md//!
				if(arguments.length !== 1)	throw jsl.ParamError()
				jsl.validate(column, "t(s+,i+)", "column")//!

				md = this.metadata()//!
				if(jsl.isNumber(column) && column >= md.length)	throw jsl.ParamError("NotDefined:column")
				if(jsl.isString(column) && !md["." + column])		throw jsl.ParamError("NotDefined:column")

				t = (jsl.isString(column) ? md["." + column] : md[column]).type
				if(t.search(/i|n/i))	throw jsl.ParamError("BadType:column:number")//!

				v = Infinity
				c	= this.column(column)

				for(var a = 0, l = c.length; a < l; a++)
					if(c[a] < v) v = c[a]

				return l ? v : null
			})
			//----------------------------------------------
			this.setFunction("max", function(column) {
				var v, t, c, md//!
				if(arguments.length !== 1)	throw jsl.ParamError()
				jsl.validate(column, "t(s+,i+)", "column")//!

				md = this.metadata()//!
				if(jsl.isNumber(column) && column >= md.length)	throw jsl.ParamError("NotDefined:column")
				if(jsl.isString(column) && !md["." + column])		throw jsl.ParamError("NotDefined:column")

				t = (jsl.isString(column) ? md["." + column] : md[column]).type
				if(t.search(/i|n/i))	throw jsl.ParamError("BadType:column:number")//!

				v =-Infinity
				c	= this.column(column)

				for(var a = 0, l = c.length; a < l; a++)
					if(c[a] > v) v = c[a]

				return l ? v : null
			})
			//----------------------------------------------
			this.setFunction("avg", function(column) {
				var v, t, c, md//!
				if(arguments.length !== 1)	throw jsl.ParamError()
				jsl.validate(column, "t(s+,i+)", "column")//!

				md = this.metadata()//!
				if(jsl.isNumber(column) && column >= md.length)	throw jsl.ParamError("NotDefined:column")
				if(jsl.isString(column) && !md["." + column])		throw jsl.ParamError("NotDefined:column")

				t = (jsl.isString(column) ? md["." + column] : md[column]).type
				if(t.search(/i|n/i))	throw jsl.ParamError("BadType:column:number")//!

				v = 0
				c	= this.column(column)

				for(var a = 0, l = c.length; a < l; a++)
					v += c[a]

				return l ? v / l : null
			})
			//----------------------------------------------
			this.setFunction("sum", function(column) {
				var v, t, c, md//!
				if(arguments.length !== 1)	throw jsl.ParamError()
				jsl.validate(column, "t(s+,i+)", "column")//!

				md = this.metadata()//!
				if(jsl.isNumber(column) && column >= md.length)	throw jsl.ParamError("NotDefined:column")
				if(jsl.isString(column) && !md["." + column])		throw jsl.ParamError("NotDefined:column")

				t = (jsl.isString(column) ? md["." + column] : md[column]).type
				if(t.search(/i|n/i))	throw jsl.ParamError("BadType:column:number")//!

				v = 0
				c	= this.column(column)

				for(var a = 0, l = c.length; a < l; a++)
					v += c[a]

				return l ? v : null
			})

			//options
			//----------------------------------------------
			jsl.Object.augment(this, jsl.OptionMap.prototype)
			this.OptionMap()

      this.option("readonly", {
        dvalue: 		false,
        validator:	"b",
        setter: 		function(v, oldv, id) {//!
        	if(this.__an || this.__un || this.__rn) throw jsl.MisuseError("OperationDenied")//!
        	return !!+v
        }
      })
			this.option("pagesize", {
				dvalue: 		10,
        validator:	"i++",
				setter:			function(v, oldv, id) { return +v }
			})
			this.option("autocommit", {
				dvalue: 		false,
        validator:	"b",
				setter:			function(v, oldv, id) { return !!+v }
			})
			this.option("refresh", {
				dvalue: 		0,
				validator:	"t(b,i+)",
				setter:			function(v, oldv, id) { return jsl.isBoolean(v) ? (v == true ? 10 : +v) : +v }
			})

			//----------------------------------------------
			p = this.prototype
			p.OptionMap()

      p.option("readonly", {
        dvalue: 		false,
        validator:	"b",
        setter: function(v, oldv, id) {//!
          if(this.__md) throw jsl.MisuseError("OperationDenied")//!
          return this.__ro = !!+v
        }
      })
			p.option("pagesize", {
				dvalue: 		10,
				validator:	"i++",
				setter:			function(v, oldv, id) { return this.__ps = +v }
			})
			p.option("autocommit", {
				dvalue: 		false,
				validator:	"b",
				setter:			function(v, oldv, id) {	return this.__ac = !!+v }
			})
			p.option("refresh", {
				dvalue: 		0,
				validator: "t(b,i+)",
				setter:	function(v, oldv, id) {
					var obj, t

					if(this.__tid) {
						jsl.removeTimer(this.__tid)
						this.__tid = null
					}

					if(+v) {
						obj = this
						t		= jsl.isBoolean(v) ? 10 : +v
						this.__tid = jsl.timer(function(){
							var id

						  if(!(obj.__rn + obj.__an + obj.__un)) obj.refresh()

						  id = obj.oid() || "DataSet"
						  jsl.console.info("info.dst.db.Refresh", [ id ])
						}, t * 1000)
					}
					return t || 0
				}
			})

			//events
			//-------------------------------------------------------------------------------
			p.EventMap()
			p.events(	"beforeRead", 	"beforeChange", "beforeUpdate",		"beforeInsert",	"beforeRemove", "beforeClear", 	"beforeFilter",
								"beforeInject",	"beforeSort",		"beforeExecute", 	"beforeRefresh","beforeCommit", "beforeRevert")

			p.events(	"read",  "change", 	"update",	  "insert",	"remove", "clear", 	 "filter", "inject",
								"sort",  "execute",	"refresh", 	"commit", "revert")

		},

		//static data
		//-------------------------------------------------------------------------------
		$__fs: {},
		$__os: {},
		$__ts: {},

		//data
		//-------------------------------------------------------------------------------

    __fs:   null,
    __os:   null,
    __ts:   null,

		//generic
    __n:    0,      //dataset number
    __id:   0,      //counter
    __md:   null,   //metadata
    __vs:   null,   //virtual
    __ft:   null,   //filter
    __lk:   false,  //lock
    __hds:  { any: 1, json: 1, xml: 1, blob: 1, d: 1 }, //high data

    __cn:   null,
    __tid:  null,   //refresh timer id

    __ds:   null,   //data
		__ods:	null,

    __ix:   0,      //index
    __lx:   0,      //logical index

    //changes
		__rm:		null,
		__am:		null,
		__um:		null,

		__rn:		0,
		__an:		0,
		__un:		0,
		__fn:		0,

    //options
    __ps:   10,
    __ac:   false,
    __ro:   false,

		//static
		//-------------------------------------------------------------------------------
		$setFilter: function(id, filter) {//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(id, 			"sr/^[^\\s&|<>=!+*\\/()@]+$", "id")
			jsl.validate(filter,	"t(f,s+)", "filter")//!

			//no string exp validation as no function internal code validation
			this.__fs["@" + id.toLowerCase()] = filter.valueOf()
			return this
		},
		//-------------------------------------------------------------------------------
		$setOrder: function(id, order) {//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(id, 		"s+", 			"id")
			jsl.validate(order,	"t(f,s+)", 	"order")//!

			this.__os["@" + id.toLowerCase()] = order.valueOf()
			return this
		},
		//-------------------------------------------------------------------------------
		$setFunction: function(id, f) {//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(id, 	"s+", "id")
			jsl.validate(f,		"f", 	"f")//!

			this.__ts["@" + id.toLowerCase()] = f
			return this
		},

		//constructor:
		//-------------------------------------------------------------------------------
		DataSet: function(metadata, options) {
			var Ds, f, md, hds, os//!
			if(arguments.length > 2)		                                         throw jsl.ParamError()
			if(arguments.length && !jsl.DataSource.DataSet.isClassOf(metadata))	 jsl.validate(metadata, "a", "metadata")//<- can be empty
			if(arguments.length === 2) 											                     jsl.validate(options, "o", "options")//!

			this.EventMap()
			this.OptionMap()

			Ds         = jsl.DataSource
			this.__cn  = this.__clone(Ds.CMemory)

      //options
      //---------------------------------------------------
      os = Ds.DataSet.options()
      if(options) os = jsl.Object.augment(os, options)
      this.set(os)

      //init
			//---------------------------------------------------
			this.__ds	  =	[]
			this.__ods  = []

			this.__rm	  =	{}
			this.__am	  =	{}
			this.__um	  =	{}
			this.__n    = Ds.DataSet.prototype.__n++

			this.__vs	  =	[]
			this.__md	  = md = arguments.length  ? Ds.__md(metadata instanceof Array ? metadata : metadata.metadata())
			                                     : []

      hds = []
			for(var a = 0, l = md.length; a < l; a++)
				if(md[a].type === "v")  this.__vs.push(md[a].id)
				else                    hds[a] = this.__hds[md[a].type]

			this.__hds  = hds

			f 					= function() {}
			f.prototype	= Ds.DataSet.__fs
			this.__fs 	= new f

			f.prototype	= Ds.DataSet.__os
			this.__os 	= new f

			f.prototype = Ds.DataSet.__ts
			this.__ts 	= new f
		},
		//-------------------------------------------------------------------------------
		type: function() {//!
			if(arguments.length)	throw jsl.ParamError()//!
			return this.__cn.type()
		},
		//-------------------------------------------------------------------------------
		connector: function() {//!
			if(arguments.length)	throw jsl.ParamError()//!
			return this.__cn.refresh ? this.__cn : null
		},
		//-------------------------------------------------------------------------------
		metadata: function(column) {
			var md//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(column, "t(i+,s+)", "column")//!

			md = this.__md

			if(arguments.length) {

				if(jsl.isString(column))	md = md["." + column]
				else											md = md[column]//!
				if(!md) throw jsl.ParamError("NotDefined:column")//!
				md = this.__clone(md)
			}
			else
				md = this.__clone(md, 2)

			return md
		},
		//-------------------------------------------------------------------------------
		count: function(pages) {
			var c//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length) 			jsl.validate(pages, "si(pages)", "pages")//!

			c = this.__ds.length - this.__fn
			c = pages ? Math.ceil(c / this.__ps) : c
			return c
		},
		//-------------------------------------------------------------------------------
		setFilter: function(id, filter) {//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(id, 			"sr/^[^\\s&|<>=!+*\\/()@]+$", "id")
			jsl.validate(filter,	"t(f,s+)", "filter")//!

			this.__fs["@" + id.toLowerCase()] = filter.valueOf()
			return this
		},
		//-------------------------------------------------------------------------------
		setOrder: function(id, order) {//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(id, 		"s+", 			"id")
			jsl.validate(order,	"t(f,s+)", 	"order")//!

			this.__os["@" + id.toLowerCase()] = order.valueOf()
			return this
		},
		//-------------------------------------------------------------------------------
		setFunction: function(id, f) {//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(id, 	"s+", "id")
			jsl.validate(f,		"f", 	"f")//!

			this.__ts["@" + id.toLowerCase()] = f
			return this
		},
		/*
			Options:
				header

				json: mode(verbose,compact), 		prettify, extended
				xml:	mode(element,attribute), 	prettify
				csv:	separator, wrapper, extended
		*/
		//-------------------------------------------------------------------------------
		toString: function(format, options) {
			var md, ml, os, fm, rs, a, l, b, s, r, sp, sp2, v, f, i, id//!lite error catch
			if(arguments.length === 2)						jsl.validate(options, 				"o", 	"options")
			if(options && options.header != null)	jsl.validate(options.header,	"b", 	"options.header")//!

      fm = jsl.isString(format) ? format.toLowerCase() : null

      if(fm === "xml" || fm === "json" || fm === "csv") {

  			md	= this.__md
  			ml	= md.length

  			os 	= options || {}
        rs  = this.__read(Infinity, 0)
        l   = rs.length

  			//1-json
  			//-----------------------------------------------------------------------
  			if(fm === "json") {//!
  				if(os.mode 			!= null)	jsl.validate(os.mode,			"si(verbose,compact)", "options.mode")
  				if(os.prettify 	!= null)	jsl.validate(os.prettify, "b", 	"options.prettify")
  				if(os.extended	!= null)	jsl.validate(os.extended, "b", 	"options.extended")//!

  				if(!os.mode || os.mode.toLowerCase() === "compact") {

  					a = 0
  					if(+os.header) {
  						r = []
  						for(b = 0; b < ml; b++) r[b] = md[b].id
  						rs.unshift(r)
  						a++
  					}

  					for(; a < l; a++) {
  						r = []
  						for(b = 0; b < ml; b++) r[b] = rs[a].r[md[b].id]
  						rs[a] = r
  					}
  				}
  				else
  					for(a = 0; a < l; a++)
  						rs[a] = rs[a].r

  				delete os.transform
  				delete os.filter

  				try 			{ s = jsl.Data.toJson(rs, os) 																		}
  				catch(e) 	{ throw (e instanceof jsl.MisuseError ? e.clearStackTrace() : e) 	}
  			}
  			//2-csv
  			//-----------------------------------------------------------------------
  			else if(fm === "csv")
  				try 			{ s = jsl.Data.toCsv(this, os) 																	  }
  				catch(e) 	{ throw (e instanceof jsl.MisuseError ? e.clearStackTrace() : e) 	}

  			//3-xml
  			//-----------------------------------------------------------------------
  			else if(fm === "xml") {//!
  				if(os.prettify 	!= null)	jsl.validate(os.prettify, "b", 	"options.prettify")
  				if(os.mode			!= null)	jsl.validate(os.mode, 		"si(element,attribute)", "options.mode")//!

  				s = []
  				a = 0
  				i = 0

  				if(os.header) 		s[i++] = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
  				if(+os.prettify)	sp = "\n\t", 	sp2 = "\n\t\t"
  				else							sp = "",			sp2 = ""

  				s[i++] = (+os.prettify ? "\n" : "") + "<rows>"

  				if(!os.mode || os.mode.toLowerCase() === "element")
  					for(a = 0; a < l; a++) {
  						s[i++] = sp + "<row>"

  						for(b = 0; b < ml; b++) {
  							id			= md[b].id
  							v				= (rs[a].r[id] + "").replace(/</g, "&lt;").replace(/&/g, "&amp;")
  							s[i++] 	= sp2 + "<" + id + ">" + v + "</" + id + ">"
  						}

  						s[i++] = sp + "</row>"
  					}

  				else {

  					f = function(s) {
  						switch(s) {
  							case "<":		return "&lt;"
  							case "&":		return "&amp;"
  							case "\"":	return "&quot;"
  							case "\n":	return "&#10;"
  							case "\r":	return "&#13;"
  						}
  					}

  					for(a = 0; a < l; a++) {
  						s[i++] = sp + "<row"

  						for(b = 0; b < ml; b++) {
  							id			= md[b].id
  							v				= (rs[a].r[id]+ "").replace(/[<&"\n\r]/g, f)
  							s[i++] 	= " " + id + "=\"" + v + "\""
  						}

  						s[i++] = " />"
  					}
  				}

  				s[i++] = (+os.prettify ? "\n" : "") + "</rows>"
  				s	= s.join("")
  			}
      }
			//-----------------------------------------------------------------------
			else
				s = "DataSet(type=" + this.type() + ", count=" + (this.__ds.length - this.__fn) + ")"

			return s
		},
		//-------------------------------------------------------------------------------
		toArray: function(objects) {
			var md, nm, b, r, d, i, rs, obj

			//!
			if(arguments.length > 1)		throw jsl.ParamError()
			if(arguments.length === 1)	jsl.validate(objects, "b", "objects")//!

			md = this.__md
			nm = md.length

			rs	= this.__read(Infinity, 0)
			obj	= objects != false

			for(var a = 0, n = rs.length; a < n; a++) {

				r = obj ? {} : []
				d = rs[a].r

				if(obj)
					for(b = 0; b < nm; b++)
						r[md[b].id] = d[md[b].id]
				else
					for(b = 0; b < nm; b++)
						r[b] = d[md[b].id]

        rs[a] = r
			}

			return rs
		},
		//-------------------------------------------------------------------------------
		valueOf: function() {
			//no error catch
			return this.__ds.length - this.__fn
		},
		//-------------------------------------------------------------------------------
		read: function(n, old) {
			try {
				var e, v, r, b, d1, d2, nr, nn, a, rs, vs, md, f//!
				if(arguments.length > 2)		throw jsl.ParamError()
				if(arguments.length)				jsl.validate(n, "t(i++,s+)", "n")
				if(arguments.length === 2)	jsl.validate(old, "si(old)", "old")
				if(this.__lk)								throw jsl.MisuseError("e.dst.Locked")//!

				e 	= new jsl.Event
				d1 	= this.hasListeners("beforeRead")
				d2 	= this.hasListeners("read")

				this.__lk = true

				nn = n
				if(nn === "*")
				  nn = Infinity

				if(jsl.isString(nn)) {//!
					if(!this.__md["." + nn]) throw jsl.ParamError("NotDefined:field")//!

					if(d1) {
						e.row	= null
						e.old	= null
						this.throwEvent("beforeRead", e)
					}

					r = this.__read(1)[0]//!
					if(!r)	throw jsl.MisuseError("e.dst.BadPosition")//!
					v = old ? r.o || r.r : r.r
					v = v[nn]

					this.__lk = false

					if(d2) {
						e.row	= r.r
						e.old	= r.o || null
						this.throwEvent("read", e)
					}
				}
				else {

					nr 	= +nn || 1
					v		= []
					a		= 0
					rs	= this.__read(nr)
          vs  = this.__vs
          md  = this.__md

				 	while(rs[a] && a < nr) {

				 		r = rs[a]

						if(d1) {
							e.row = null
							e.old = null
							this.throwEvent("beforeRead", e)
						}

						v[a] = this.__cloneR(old ? r.o || r.r : r.r)

						for(b = 0; b < vs.length; b++) {
							f = md["." + vs[b]].value
						  v[a][vs[b]] = f(v[a])
						}

            if(!rs[++a] || a === nr) this.__lk = false

						if(d2) {
							e.row = r.r
							e.old = r.o || null
							this.throwEvent("read", e)
						}
					}

					//if we do not enter in the while
					this.__lk = false
					if(nr === 1) 	v = v[0] || null
					else					v = v.length ? v : null
				}

				return v
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		update: function(field, value) {
			try {
				var e, nrs, id, md, mr, bm, a, l, r, n, d, b, nr, vs, rs, cl

				//!
				if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
				jsl.validate(field, "t(o,s+,i+)", "field")
				if(this.__ro)	throw jsl.MisuseError("e.dst.ReadOnly")
				if(this.__lk)	throw jsl.MisuseError("e.dst.Locked")//!

				e		= new jsl.Event
				md	= this.__md
				cl  = this.__clone

				//1-name
				if(jsl.isString(field)) {//!
					if(!md["." + field])			throw jsl.ParamError("NotDefined:field")
					if(arguments.length < 2)	throw jsl.ParamError("Required:value")
					this.__type(field, value)//!

					nrs 					= [{}]
					nrs[0][field]	= value
				}
				//2-index
				else if(jsl.isNumber(field)) {//!
					if(field >= md.length)			throw jsl.ParamError("NotDefined:field")
					if(arguments.length < 2)		throw jsl.ParamError("Required:value")//!

					id = md[field].id//!
					this.__type(id, value)//!

					nrs 				= [{}]
					nrs[0][id] 	= value
				}
				//3-rows
				else {//!
					if(arguments.length === 2)	throw jsl.ParamError("NotRequired:value")//!
					nrs = field instanceof Array ? field.slice() : [ field ]

					for(a = 0, l = nrs.length; a < l; a++) {
						r = nrs[a]

						if(r instanceof Array) {
							d = r
							r = {}//!
							if(d.length > md.length)	throw jsl.ParamError("e.dst.BadRowSize:rows[" + a + "]")//!
							for(b = 0; b < d.length; b++) r[md[b].id] = d[b]
						}//!
						else
							jsl.validate(r, "o", "rows[" + a + "]")//!

						//!
						for(b = 0; b < md.length; b++) {
							d = md[b]
							if(d.id in r) this.__type(d.id, r[d.id], "rows[" + a + "](" + d.id + ")")
						}//!
						nrs[a] = r
					}
				}

				mr 	= jsl.Object.augment
				vs	= this.__vs
				bm 	= 16

				if(this.hasListeners("beforeUpdate"))	bm += 1
				if(this.hasListeners("beforeChange"))	bm += 2
				if(this.hasListeners("change"))				bm += 4
				if(this.hasListeners("update"))				bm += 8

				n = nrs.length
				a = 0

				if(n) {
  				rs = this.__read(n)//!
          if(rs.length !== n) throw jsl.ParamError("e.dst.BadPosition")//!
          this.__lk = true
				}
				else
				  rs = []

				while(rs[a] && n--)	{

					r = rs[a]

					//1-new row
					//---------------------------------------------------------------------
					nr = mr(cl(r.r), nrs[a++])

					if(vs.length)
						for(b = 0, l = vs.length; b < l; b++)
							try 			{ nr[vs[b]] = md["." + vs[b]].value(nr) }
							catch(er)	{ throw jsl.ParamError("e.dst.BadVirtual:rows[" + a + "](" + vs[b] + ")", er) }

					//2-change inspection
					//---------------------------------------------------------------------
					bm = bm - 16

					for(id in nr)
						if(md["." + id] && r.r[id] !== nr[id]) {
							bm += 16
							break
						}

					//3-events
					//---------------------------------------------------------------------
					if(bm & 15) {
						e.row = nr
						e.old	= r.o || r.r

						if(bm & 1) this.throwEvent("beforeUpdate", e)

						if(bm & 2 && bm & 16) {
							e.operation = "update"
							this.throwEvent("beforeChange", e)
						}
					}

					//4-save row
					//---------------------------------------------------------------------
					if(bm & 16) {

						//unchanged
						if(!r.s) {
							r.o = r.r
							r.r	= nr
							r.s = 1
							this.__um[r.id] = r
							this.__un++
						}
						//added/already updated
						else
							r.r = nr

						//5-filter
						//---------------------------------------------------------------------
						if(this.__ft) {

							try 			{ r.f = !!this.__ft(nr)								   											}
							catch(er)	{ throw jsl.ScriptError("e.dst.BadFilter:rows[" + a + "]", er)}

							if(r.f)
								this.__fn++
						}
					}

					if(!n) this.__lk = false

					//6-events
					//---------------------------------------------------------------------
					if(bm & 12) {
						if(bm & 4 && bm & 16) {
							e.operation = "update"
							this.throwEvent("change", e)
						}
						if(bm & 8) this.throwEvent("update", e)
					}
				}

				if(this.__ac) this.commit()
				return this
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		insert: function(rows) {
			try {
				var md, rs, l, n, a, b, d, ds, r, e, vs, ix, vl, ml, bm, id

				//!
				if(arguments.length > 1)	throw jsl.ParamError()
				if(arguments.length)			jsl.validate(rows, "t(o,i++)", "rows")
				if(this.__ro)             throw jsl.MisuseError("e.dst.ReadOnly")
				if(this.__lk)             throw jsl.MisuseError("e.dst.Locked")//!

				ix = this.__ix//!
				if(this.__lx > this.count())	throw jsl.ParamError("e.dst.BadPosition")//!

				md = this.__md
				ml = md.length

				//1-number
				if(!arguments.length || jsl.isNumber(rows)) {

					rs	= []
					n		= +rows || 1

					for(a = 0; a < n; a++) {
						rs[a] = {}
						for(b = 0; b < ml; b++)  {
							d = md[b]
							if(d.type !== "v") rs[a][d.id] = d.value
						}
					}
				}
				//2-rows
				else {
					rs = rows instanceof Array ? rows.slice() : [ rows ]

					for(a = 0, l = rs.length; a < l; a++) {
						r = rs[a]

						if(r instanceof Array) {
							d 	= r
							r 	= {}//!
							if(d.length > md.length)	throw jsl.ParamError("e.dst.BadRowSize:rows[" + a + "]")//!
							for(b = 0; b < d.length; b++) r[md[b].id] = d[b]
						}
						else {//!
							jsl.validate(r, "o", "rows[" + a + "]")//!
							//no complete object cloning -> only the columns must be taken into account
              d = r
              r = {}
              for(b = 0; b < ml; b++) {

                id = md[b].id
                if(d.hasOwnProperty(id))
                  r[id] = d[id]
              }
						}

						for(b = 0; b < ml; b++) {
							d = md[b]
							if(!(d.id in r) && d.type !== "v") r[d.id] = d.value//!
							else             this.__type(d.id, r[d.id], "rows[" + a + "](" + d.id + ")")//!
						}

						rs[a] = r
					}
				}

				e 	= new jsl.Event
				ds	= this.__ds
				vs	= this.__vs
				n 	= 0

				bm = 0
				if(this.hasListeners("beforeInsert"))	bm += 1
				if(this.hasListeners("beforeChange"))	bm += 2
				if(this.hasListeners("change"))				bm += 4
				if(this.hasListeners("insert"))				bm += 8

				this.__lk = true
				for(a = 0, l = rs.length; a < l; a++) {

					if(vs.length)
						for(b = 0, vl = vs.length; b < vl; b++)
							try 			{ rs[a][vs[b]] = md["." + vs[b]].value(rs[a]) }
							catch(er)	{ throw jsl.ParamError("e.dst.BadVirtual:rows[" + a + "](" + vs[b] + ")", er) }

					if(bm) {
						e.row = rs[a]
						e.old = null
						if(bm & 1) this.throwEvent("beforeInsert", e)

						if(bm & 2) {
							e.operation = "insert"
							this.throwEvent("beforeChange", e)
						}
					}

					r 		  = { }
					r.__$r  = true
					r.s		  = 2
					r.r 	  = rs[a]
					r.id	  = this.__id++

					if(ix < ds.length) ds.splice(ix, 0, r)
					else               ds[ix] = r

					ix++
					this.__am[r.id] = r
					this.__an++

					if(this.__ft) {

						try 			{ r.f = !!this.__ft(r.r)																			}
						catch(er) { throw jsl.ScriptError("e.dst.BadFilter:rows[" + a + "]", er)}

						if(r.f)
							this.__fn++
					}

					if(a === l - 1)	this.__lk = false
					if(bm & 4) this.throwEvent("change", e)
					if(bm & 8) this.throwEvent("insert", e)
				}

				this.__lk = false
				if(this.__ac) this.commit()
				return this
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		append: function(rows) {
			var i

			try {
				i = this.__lx
				this.end()

				this.insert.apply(this, arguments)
				this.index(i)
			}
			catch(e) {
				this.index(i)
				throw e instanceof jsl.MisuseError ? e.clearStackTrace() : e
			}
			return this
		},
		//-------------------------------------------------------------------------------
		remove: function(n) {
			try {
				var e, ds, r, bm, nr, a, rs, i

				//!
				if(arguments.length > 1)	throw jsl.ParamError()
				if(arguments.length)			jsl.validate(n, "i++", "n")
				if(this.__ro)		          throw jsl.MisuseError("e.dst.ReadOnly")
				if(this.__lk)							throw jsl.MisuseError("e.dst.Locked")//!

				this.__lk = true
				e	  = new jsl.Event
				ds  = this.__ds

				bm = 0
				if(this.hasListeners("beforeRemove"))	bm += 1
				if(this.hasListeners("beforeChange"))	bm += 2
				if(this.hasListeners("change"))				bm += 4
				if(this.hasListeners("remove"))				bm += 8

				nr = +n || 1
				rs = this.__read(nr)
				a	 = 0

				while(rs[a] && a < nr) {

					r = rs[a]

					//1-events
					//-------------------------------------------------------------------
					if(bm) {
						e.row = r.r
						e.old = r.o || null
						if(bm & 1) this.throwEvent("beforeRemove", e)
						if(bm & 2) {
							e.operation = "remove"
							this.throwEvent("beforeChange", e)
						}
					}

					//2-remove
					//-------------------------------------------------------------------
					ds.splice(r.ix - a++, 1)
					if(r.f) this.__fn--

					if(!r.s) {
						this.__rm[r.id] = r
						this.__rn++
					}
					else if(r.s === 1) {
						delete this.__um[r.id]
						this.__un--
						this.__rm[r.id] = r
						this.__rn++

						r.r = r.o
					}
					else if(r.s === 2) {
						delete this.__am[r.id]
						this.__an--
					}

					if(!rs[a] || a === nr)	this.__lk = false

					//3-events
					//-------------------------------------------------------------------
					if(bm & 4) this.throwEvent("change", e)
					if(bm & 8) this.throwEvent("remove", e)
				}

				//if we do not enter in the while
				this.__lk = false
				if(this.__ac)	this.commit()
				return this
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		clear: function(rule) {
			try {
				var e, r, b, rs, n

				//!
				if(arguments.length > 1)	throw jsl.ParamError()
				if(arguments.length)			jsl.validate(rule, "f", "rule")
				if(this.__ro)		          throw jsl.MisuseError("e.dst.ReadOnly")
				if(this.__lk)							throw jsl.MisuseError("e.dst.Locked")//!

				this.__lk = true
				e         = new jsl.Event
				e.rule    = rule

				this.throwEvent("beforeClear", e)
        this.__lk = false

				this.__ix = 0
				if(rule) {

					n  = 0
					rs = this.__read(Infinity)
					for(var a = 0, l = rs.length; a < l; a++) {

						r = rs[a]
						try 			{ b = rule(r.r) }
						catch(er)	{	throw jsl.ParamError("BadScript:rule", er) }

						if(b)	{
  					  this.__ix = r.ix - n
  					  this.remove()
  					  n++
						}
					}
				}
				else if(this.count())
					this.remove(this.count())

				this.__ix = this.__index()
				this.throwEvent("clear", e)

				if(this.__ac) this.commit()
				return this
			}
			catch(e) {
				this.__lk = false
        this.__ix = this.__index()
				throw e
			}
		},
		/*
		  data:
		    XNode, XNode[], DataSet, Array

		  options:
		    xml(mode):      element, attribute, custom
		    xml(transform): f
		*/
		//-------------------------------------------------------------------------------
		inject: function(data, options) {
			try {
				var rs, md, m, b, ml, r, e, v, re, Data, t, XN//!
				if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
				if(arguments.length === 2) 										jsl.validate(options, "o", "options")
				if(this.__ro)		           										throw jsl.MisuseError("e.dst.ReadOnly")
				if(this.__lk)																	throw jsl.MisuseError("e.dst.Locked")
				if(this.__lx > this.count())									throw jsl.ParamError("e.dst.BadPosition")//!

				this.__lk = true

				e 				= new jsl.Event
				e.data 		= data
				e.options	= options

				this.throwEvent("beforeInject", e)
				Data 	= jsl.Data
				XN 		= Data.XNode

				//1-xml
				if(XN.isClassOf(data) || (data instanceof Array && XN.isClassOf(data[0]))) {//!
					if(options && options.mode)                                    jsl.validate(options.mode, "si(element,attribute,custom)", "options.mode")
					if(options && options.mode == "custom" && !options.transform)	 throw jsl.ParamError("Required:options.transform")
					if(options && options.transform)	                             jsl.validate(options.transform, "f", "options.transform")//!

					rs = XN.isClassOf(data[0]) ? data : data.children()
					md = this.__md
					ml = md.length

					if(options)
						if(options.mode == "attribute")		m = 1
						else if(options.mode == "custom")	m = 2

					for(var a = 0, l = rs.length; a < l; a++) {

						if(m === 2) {
							try 			{ r = options.transform(rs[a]) 														}
							catch(er) { throw jsl.ParamError("BadScript:options.transform", er)	}

							//!
							if(typeof r !== "object")  throw jsl.ParamError("BadReturnValue:options.transform:object")//!
						}
						else {

							r = {}
							for(b = 0; b < ml; b++) {

								if(!m)	v = rs[a].select(md[b].id + "[1]"), v = v && (v.firstChild() || v).value()
								else		v = rs[a].attribute(md[b].id)

								t 	= md[b].type
								re	= /^[in]/i

								if(re.test(t))											r[md[b].id] = +v
								else if(t === "b" && v == "true")		r[md[b].id] = true
								else if(t === "b" && v == "false")	r[md[b].id] = false
								else if(t === "d")									r[md[b].id] = new Date(+v)
								else if(t === "xml")								r[md[b].id] = Data.fromXml(rs[a], 	{ validate: true })
								else if(t === "json")								r[md[b].id] = Data.fromJson(rs[a],	{ extended: true })
								else if(t === "any")								r[md[b].id] = Data.deserialize(rs[a])
								else if(t === "blob")								r[md[b].id] = new Data.Blob(Data.Bolb.H + rs[a])
							}
						}

						rs[a] = r
					}
				}

				//2-dataset
				else if(jsl.DataSource.DataSet.isClassOf(data))
					rs = data.rows()

				//3-array
				else if(data instanceof Array)
					rs = data

				//!4-error
				else
					throw jsl.ParamError("BadType:data")//!

				this.__lk = false
				this.insert(rs)

				e.rows = rs
				this.throwEvent("inject", e)
				if(this.__ac) this.commit()
				return this
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		filter: function(filter) {
			try {
				var f, params, s, e, rs, a, l, nf, ds

				//!
				if(arguments.length)  jsl.validate(filter, "t(s+,f)", "filter")
        if(this.__lk)					throw jsl.MisuseError("e.dst.Locked")//!

				//filter build
        //-------------------------------------------------
				params 	= Array.prototype.slice.call(arguments, 1)
				s				= jsl.isString(filter)

				//1-filter id
				if(s && !filter.search(/^@[^\s&|<>=!+*\/()@]+$/)) {//!
					if(!this.__fs[filter.toLowerCase()])	throw jsl.ParamError("NotDefined:filter(id)")//!
					f = this.__fs[filter.toLowerCase()]
					s	= jsl.isString(f)
				}
				//2-filter literal (string or function)
				else
					f = filter && filter.valueOf()

				if(s)
					f = this.__exp(f, params)

				else if(params.length) {
					nf = f
					params.unshift(null)
					f = function(r) { params[0] = r; return nf.apply(jsl.__go, params) }
					f.nf = nf + params.slice(1).join("")
				}

        //-------------------------------------------------
				if((this.__ft ? (this.__ft.nf || this.__ft) : null) + "" !== (f ? (f.nf || f) : null) + "") {

					this.__ft = f

					e	= new jsl.Event
					e.params = params
					e.filter = filter

					this.__lk = true
					this.throwEvent("beforeFilter", e)

					if(!f) {
						rs = this.__ds
						for(a = 0, l = rs.length; a < l; a++) rs[a].f = false
						this.__ix	= this.__lx
						this.__fn = 0
					}
					else
            this.__filter()

					this.__lk = false
					this.throwEvent("filter", e)
				}

				return this
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		sort: function(order) {
			try {
				var params, o, s, data, md, a, l, d, f, e

				//!
				if(!arguments.length)	throw jsl.ParamError()
				jsl.validate(order, "t(s+,f)", "order")
				if(this.__lk) throw jsl.MisuseError("e.dst.Locked")//!

				params 	= Array.prototype.slice.call(arguments, 1)
				s				= jsl.isString(order)

				if(s && order.charAt(0) === "@") {//!
					if(!this.__os[order.toLowerCase()])	throw jsl.ParamError("NotDefined:order(id)")//!
					o = this.__os[order.toLowerCase()]
					s	= jsl.isString(o)
				}
				else
					o = order

				if(s) {//!
					if(arguments.length > 1)	throw jsl.ParamError()//!

					data = o.replace(/\s+/g, "")//!
					if(!(/^([^:,]+(:(asc|des))?(,(?!$)|$))+/i).test(data))	throw jsl.ParamError("SyntaxError:order")//!

					md 		= this.__md
					data	= data.split(",")

					for(a = 0, l = data.length; a < l; a++) {
						data[a] = d = data[a].split(":")//!
						if(!md["." + d[0]])	throw jsl.ParamError("NotDefined:order(column=" + d[0] + ")")//!

						d[1] = !d[1] || d[1].toLowerCase() === "des"
					}
				}

				e 				= new jsl.Event
				e.order 	= order
				e.data		= data
				e.params	= params

				this.__lk = true
				this.throwEvent("beforeSort", e)

 				this.__read(Infinity, 0)

				//1-string sort
				if(s) {
					f 			= this.__sort
					f.data 	= data
					this.__ds.sort(f)
				}
				//2-function sort
				else {

					params.unshift(null, null)

					this.__ds.sort(function(r1, r2) {
						params[0] = r1.r
						params[1] = r2.r
						try 			{ return o.apply(this, params) ? -1 : 1				}
						catch(er) { throw jsl.ParamError("BadScript:order", er) }
					})
				}

				if(this.__ft)
  				this.__ix = this.__index()

				this.__lk = false
				this.throwEvent("sort", e)

				return this
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		execute: function(f) {
			try {
				var action, v, args, e//!
				jsl.validate(f, "t(s+,f)", "f")
				if(jsl.isString(f) && f.charAt(0) !== "@")	throw jsl.ParamError("e.dst.BadId")//!

				if(jsl.isString(f))	action = this.__ts[f.toLowerCase()]
				else								action = f//!
				if(!action)	throw jsl.ParamError("NotDefined:id")//!

				args = Array.prototype.slice.call(arguments, 1)

				e = new jsl.Event
				e.action = f
				e.params = args

				this.__lk = true
				this.throwEvent("beforeExecute", e)

				try 			{	v = action.apply(this, args) 						  }
				catch(er)	{	throw jsl.ScriptError("BadScript:f", er)  }

				this.__lk = false
				this.throwEvent("execute", e)
				return v
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		rows: function(filter) {
			var dt, l, rs, a, b, mp, id, i1, i2, n, n1, n2//!
			if(arguments.length > 2)	                          throw jsl.ParamError()
      if(arguments.length === 1 &&  jsl.isNumber(filter)) jsl.validate(filter, "i", "i1")
      if(arguments.length === 2)                          jsl.validate(arguments[0], "i", "i1"),
                                                          jsl.validate(arguments[1], "i", "i2")//!

      a = 0

      //1-slice mode
      if(jsl.isNumber(filter)) {

      	i1 = filter
      	i2 = arguments[1]

        n  = this.count()
        n1 = i1 < 0 ? n + i1 : (+i1 || 0)
        n2 = i2 < 0 ? n + i2 : (+i2 || n)
        n  = n2 - n1

        if(n > 0) {
          rs = this.__read(n, this.__index(n1))

          for(l = rs.length; a < l; a++)
            rs[a] = this.__cloneR(rs[a].r)
        }
        else
          rs = []
      }
      //2-filter mode
      else {//!
				if(arguments.length === 1 && !jsl.isFunction(filter))
					jsl.validate(filter, "sr/^(=|\\+|-|!|!!|\\*)$", "filter")//!

        rs  = []
        dt  = !jsl.isString(filter) || filter == "=" ? this.__read(Infinity, 0) : null
        l   = dt && dt.length
        b   = 0

        //1-no filter
        if(!filter)
          for(;a < l; a++)
            rs[a] = this.__cloneR(dt[a].r)

        //2-function filter
        else if(jsl.isFunction(filter))
          for(;a < l; a++)
            try       { if(filter(dt[a].r)) rs[b++] = this.__cloneR(dt[a].r) }
            catch(e)  { throw jsl.ParamError("BadScript:filter", e) }

        //3-unchanged rows
        else if(filter == "=") {
          for(;a < l; a++)
            if(!dt[a].s)
              rs[b++] = this.__cloneR(dt[a].r)
        }

        //4-changed rows
        else if(filter == "!") {

          mp = this.__um
          for(id in mp)
            rs[a++] = this.__cloneR(mp[id].r)
        }

        //5-old rows
        else if(filter == "!!") {

          mp = this.__um
          for(id in mp)
            rs[a++] = this.__cloneR(mp[id].o)
        }

        //5-new rows
        else if(filter == "+") {

          mp = this.__am
          for(id in mp)
            rs[a++] = this.__cloneR(mp[id].r)
        }

        //6-removed rows
        else if(filter == "-") {

          mp = this.__rm
          for(id in mp)
            rs[a++] = this.__cloneR(mp[id].r)
        }

        //7-added, removed, changed
        else if(filter == "*") {

          mp = this.__um
          for(id in mp)
            rs[a++] = this.__cloneR(mp[id].r)

          mp = this.__am
          for(id in mp)
            rs[a++] = this.__cloneR(mp[id].r)

          mp = this.__rm
          for(id in mp)
            rs[a++] = this.__cloneR(mp[id].r)
        }
      }

			return rs
		},
    //-------------------------------------------------------------------------------
    column: function(id, filter) {
      var dt, l, rs, a, b, mp, i1, i2, n, n1, n2, cid//!
      if(!arguments.length || arguments.length > 3)       throw jsl.ParamError()
      jsl.validate(id, "t(s+,i+)", "id")
      if(arguments.length === 2 && !jsl.isNumber(filter)) jsl.validate(filter, "t(f,sr/^(=|\\+|-|!|!!|\\*)$)", "filter")
      if(arguments.length === 2 &&  jsl.isNumber(filter)) jsl.validate(filter, "i", "i1")
      if(arguments.length === 3)                          jsl.validate(arguments[1], "i", "i1"),
                                                          jsl.validate(arguments[2], "i", "i2")//!
      a = 0
      if(jsl.isString(id)) {//!
        if(!this.__md["." + id]) throw jsl.ParamError("NotDefined:id")//!
        cid = id + ""
      }
      else {//!
        if(!this.__md[id]) throw jsl.ParamError("BadValue:id")//!
        cid = this.__md[id].id
      }

      //1-slice mode
      if(jsl.isNumber(filter)) {

        i1 = filter
        i2 = arguments[2]

        n  = this.count()
        n1 = i1 < 0 ? n + i1 : (+i1 || 0)
        n2 = i2 < 0 ? n + i2 : (+i2 || n)
        n  = n2 - n1

        if(n > 0) {
          rs = this.__read(n, this.__index(n1))

          for(l = rs.length; a < l; a++)
            rs[a] = rs[a].r[cid]
        }
        else
          rs = []
      }
      //2-filter mode
      else {

        rs  = []
        dt  = !jsl.isString(filter) || filter == "=" ? this.__read(Infinity, 0) : null
        l   = dt && dt.length
        b   = 0

        //1-no filter
        if(!filter)
          for(;a < l; a++)
            rs[a] = dt[a].r[cid]

        //2-function filter
        else if(jsl.isFunction(filter))
          for(;a < l; a++)
            try       { if(filter(dt[a].r)) rs[b++] = dt[a].r[cid]  }
            catch(e)  { throw jsl.ParamError("BadScript:filter", e) }

        //3-unchanged rows
        else if(filter == "=") {
          for(;a < l; a++)
            if(!dt[a].s)
              rs[b++] = dt[a].r[cid]
        }

        //4-changed rows
        else if(filter == "!") {

          mp = this.__um
          for(id in mp)
            rs[a++] = mp[id].r[cid]
        }

        //5-old rows
        else if(filter == "!!") {

          mp = this.__um
          for(id in mp)
            rs[a++] = mp[id].o[cid]
        }

        //5-new rows
        else if(filter == "+") {

          mp = this.__am
          for(id in mp)
            rs[a++] = mp[id].r[cid]
        }

        //6-removed rows
        else if(filter == "-") {

          mp = this.__rm
          for(id in mp)
            rs[a++] = mp[id].r[cid]
        }

        //7-added, removed, changed
        else if(filter == "*") {

          mp = this.__um
          for(id in mp)
            rs[a++] = mp[id].r[cid]

          mp = this.__am
          for(id in mp)
            rs[a++] = mp[id].r[cid]

          mp = this.__rm
          for(id in mp)
            rs[a++] = mp[id].r[cid]
        }
      }

      return rs
    },
		//-------------------------------------------------------------------------------
		walk: function(action) {
			var rs//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(action, "f", "action")//!

			rs = this.__read(Infinity, 0)

			try 			{ for(var a = 0, l = rs.length; a < l; a++) if(action(rs[a].r)) break }
			catch(e) 	{ throw jsl.ScriptError("BadScript:action", e) }

			return this
		},
		//-------------------------------------------------------------------------------
		refresh: function() {
			try {
				var e, ds//!
				if(arguments.length) throw jsl.ParamError()
				if(this.__lk) throw jsl.MisuseError("e.dst.Locked")
  			if(this.__rn + this.__an + this.__un)	throw jsl.MisuseError("e.dst.RefreshNegated")//!

				if(this.__cn.refresh) {

					this.__lk = true

					e  = new jsl.Event
					this.throwEvent("beforeRefresh", e)

					this.__um = {}
					this.__am = {}
					this.__rm = {}

					this.__un = 0
					this.__an = 0
					this.__rn = 0

          this.__fn = 0

          if(this.__cn.ASY) {

          	ds = this
            this.__cn.refresh(function(rows) {

            	ds.__ds = rows
            	ds.__filter()
              ds.__lk = false
              ds.throwEvent("refresh", e)
            })
          }
          else {
            this.__ds = this.__cn.refresh()
            this.__filter()
            this.__lk = false
  					this.throwEvent("refresh", e)
          }
				}

				return this
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		commit: function() {
			try {
				var a, um, rm, om, am, mp, id, e, ds, f//!
				if(arguments.length) 	throw jsl.ParamError()
				if(this.__lk)					throw jsl.MisuseError("e.dst.Locked")//!

        if(this.__an || this.__un || this.__rn) {

    			um 	= []
    			om  = []
    			am 	= []
    			rm 	= []

    			if(this.__un) {
    				a	 = 0
    				mp = this.__um
    				for(id in mp) um[a++] = mp[id].r
    			}

          if(this.__un) {
            a  = 0
            mp = this.__um
            for(id in mp) om[a++] = mp[id].o
          }

    			if(this.__an) {
    				a	 = 0
    				mp = this.__am
    				for(id in mp) am[a++] = mp[id].r
    			}

    			if(this.__rn) {
    				a	 = 0
    				mp = this.__rm
    				for(id in mp) rm[a++] = mp[id].r
    			}

  				e 				 = new jsl.Event
  				e.updated  = um
  				e.old      = om
  				e.added    = am
  				e.removed  = rm

  				this.__lk = true
  				this.throwEvent("beforeCommit", e)

          ds  = this
  				f   = function() {
            var am, um, id

            am = ds.__am
            um = ds.__um

            for(id in um) um[id].s = null, um[id].o = null
            for(id in am) am[id].s = null

            ds.__um = {}
            ds.__am = {}
            ds.__rm = {}

            ds.__un = 0
            ds.__an = 0
            ds.__rn = 0

            ds.__ods  = ds.__ds.slice()
            ds.__lk   = false
            ds.throwEvent("commit", e)
          }

					if(this.__cn.ASY)
            this.__cn.commit({ added: am, updated: um, removed: rm, old: om }, f)
					else {
            this.__cn.commit({ added: am, updated: um, removed: rm, old: om })
            f()
					}
        }

				return this
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//-------------------------------------------------------------------------------
		revert: function() {
			try {
				var e, ds, id, mp, obj//!
				if(arguments.length) 	throw jsl.ParamError()
				if(this.__lk)					throw jsl.MisuseError("e.dst.Locked")//!

				if(this.__an || this.__un || this.__rn) {

					e = new jsl.Event
					this.__lk = true
					this.throwEvent("beforeRevert", e)

					this.__ds = this.__ods.slice()

					mp = this.__um
					for(id in mp) {
						obj = mp[id]
            obj.r = obj.o
            obj.o = null
            obj.s = null
					}

          //we cannot use the maps because: commit().refresh().revert()
          //the revert is not able to build the initial situation after the commit
          //moment if a refresh has loaded different data
          this.__filter()

					this.__um = {}
					this.__am = {}
					this.__rm = {}

					this.__un = 0
					this.__an = 0
					this.__rn = 0

					this.__lk = false
					this.throwEvent("revert", e)
				}

				return this
			}
			catch(e) {
				this.__lk = false
				throw e
			}
		},
		//seek
		//-------------------------------------------------------------------------------
		top: function() {//!
			if(arguments.length) 	throw jsl.ParamError()
			if(this.__lk)					throw jsl.MisuseError("e.dst.Locked")//!

			this.__ix = 0
			this.__lx = 0
			return this
		},
		//-------------------------------------------------------------------------------
		end: function() {
			var i//!
			if(arguments.length)	throw jsl.ParamError()
			if(this.__lk)					throw jsl.MisuseError("e.dst.Locked")//!

			i					= this.count()
			this.__lx = i
			this.__ix = i + this.__fn
			return this
		},
		//-------------------------------------------------------------------------------
		index: function(ix) {
			var i//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(ix, "i", "ix")//!

			if(arguments.length) {//!
        if(this.__lk) throw jsl.MisuseError("e.dst.Locked")//!

        i = ix >= 0 ? +ix : this.count() + ix

        if(i !== this.__lx)
  				if(!i)
  					this.__lx = this.__ix = 0
  				else {
            //!
  					if(i < 0)	throw jsl.MisuseError("e.dst.NegativePosition")//!
  					this.__lx = i
  					this.__ix = this.__fn ? this.__index() : i
  				}
  		}

			return arguments.length ? this : this.__lx
		},
		//-------------------------------------------------------------------------------
		next: function(n) {
			var ix, i, ds, nr//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(n, "i++", "n")
			if(this.__lk)							throw jsl.MisuseError("e.dst.Locked")//!

			nr = +n || 1

			if(this.__ft) {
				ds = this.__ds
				ix = this.__ix + 1
				i	 = nr

				while(i) {
					if(!ds[ix] || !ds[ix].__$r || !ds[ix].f) i--
					ix++
				}

				this.__lx += nr
				this.__ix  = ix - 1
			}
			else
				this.__ix = this.__lx += nr

			return this
		},
		//-------------------------------------------------------------------------------
		prev: function(n) {
			var ix, i, ds, nr//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(n, "i++", "n")
			if(this.__lk)							throw jsl.MisuseError("e.dst.Locked")//!

			nr = +n || 1

			if(this.__ft) {
				ds	= this.__ds
				ix 	= this.__ix - 1
				i		= nr

				while(i) {
					if(!ds[ix] || !ds[ix].__$r || !ds[ix].f) i--
					ix--
				}

				ix++//!
				if(ix < 0)	throw jsl.ParamError("e.dst.NegativePosition")//!

				this.__lx -= nr
				this.__ix  = ix
			}
			else {//!
				if(this.__ix - nr < 0)	throw jsl.ParamError("e.dst.NegativePosition")//!
				this.__ix = this.__lx -= nr
			}
			return this
		},
		//-------------------------------------------------------------------------------
		page: function(ix) {
			var p//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(ix, "i", "ix")//!

			if(arguments.length)
				try 			{ p = this.index(ix * this.__ps) }
				catch(e) 	{ throw e instanceof jsl.MisuseError ? e.clearStackTrace() : e }

			return arguments.length ? this : Math.floor(this.__lx / this.__ps)
		},
		//-------------------------------------------------------------------------------
		nextPage: function(n) {
			var i//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(n, "i++", "n")//!

			i = ((+n || 1) - 1) * this.__ps
			i = this.__ps - this.__lx % this.__ps + i

			try 			{ this.next(i) }
			catch(e) 	{ throw e instanceof jsl.MisuseError ? e.clearStackTrace() : e }
			return this
		},
		//-------------------------------------------------------------------------------
		prevPage: function(n) {
			var i//!
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(n, "i++", "n")//!

      i = (+n || 1) * this.__ps
      i = this.__lx % this.__ps + i

			try 			{ this.prev(i) }
			catch(e) 	{ throw (e instanceof jsl.MisuseError ? e.clearStackTrace() : e) }
			return this
		},
		//private
		//-------------------------------------------------------------------------------
		__filter: function() {
      var ft, fn, ds, ix

      ft = this.__ft
      if(ft) {

        fn = 0
        ix = this.__lx
        ds = this.__ds
        this.__read(Infinity, 0)

        try {
          for(var a = 0, n = ds.length; a < n; a++)
            if((ds[a].f = !!ft(ds[a].r))) {
              if(ix >= a) ix++
              fn++
            }
        }
        catch(er) {
          throw jsl.ParamError("e.dst.BadFilter", er)
        }

        this.__fn = fn
        this.__ix = ix
      }
		},
    //-------------------------------------------------------------------------------
		__read: function(n, ix) {
			var ds, md, nm, ft, rs, a, r, b, fn, id, hds, mdb, lk

			ds	= this.__ds
			md	= this.__md
			ft  = this.__ft
			hds = this.__hds

			nm  = md.length
      fn  = jsl.DataSource.__fromNative

			n		= n || 1
			ix	= ix != null ? ix : this.__ix

      a   = 0
			rs	= []

			do {

				r = ds[ix]

				if(r) {
				  //__$ decoration because these flags can be tested on a row loaded from the datasource
				  //but not yet exploded. In this way  p(name collision) is reduced

  				//row to explode
  				if(!r.__$r) {

  					//1-array row
  					//in this case the datasource cannot put extra data on the row
            if(r instanceof Array) {

              r = {}
              for(b = 0; b < nm; b++) {
              	mdb   = md[b]
                id    = mdb.id
                r[id] = hds[b] ? fn(ds[ix][b], mdb.type, "rows[" + ix + "]." + id) : ds[ix][b]
              }
            }
            //2-object row
            //the row object is taken as is with also extra hidden data
            else
              for(b = 0; b < nm; b++)
              	if(hds[b]) {
                  id    = md[b].id
                  r[id] = fn(r[id], md[b].type, "rows[" + ix + "]." + id)
                }

            r = ds[ix] = { r: r, id: this.__id++, __$r: true }
					}

          if(!r.f) {
            rs[a++] = r
            r.ix    = ix
          }

          ix++
				}
			}	while(r && a < n)

			return rs
		},
		//-------------------------------------------------------------------------------
		__index: function(lx) {
			var ds, n, i

			lx = lx == null ? this.__lx : lx

			if(this.__fn) {

				ds = this.__ds

				i	= 0
				n = lx + 1
				while(n) {
					if(!ds[i] || !ds[i].__$r || !ds[i].f) n--
					i++
				}

				i--
			}
			else
				i = lx

			return i
		}
	})
	//i, i+, i++, n, n+, n++, s, s+, v, b, d, any, blob, xml, json
	//-------------------------------------------------------------------------------
	jsl.DataSource.DataSet.prototype.__type = function(field, value, cx) {
		var t

		cx	= cx || "value"
		t		= this.__md["." + field].type

		switch(t) {

			case "blob":
				if(value != null && !(jsl.Data.Blob.isClassOf(value)))	throw jsl.ParamError("BadType:" + cx + ":jsl.Data.Blob")
				break

			case "xml":
				if(value != null && !(jsl.Data.XNode.isClassOf(value)))	throw jsl.ParamError("BadType:" + cx + ":jsl.Data.XNode")
				break

			case "any":
				break

			case "json":
				if(value != null && !jsl.isObject(value))	throw jsl.ParamError("BadType:" + cx + ":object")
				break

			case "v":
			  //virtual fields are skipped
				break

			default:
				jsl.validate(value, t, cx)
		}
 	}
	//-------------------------------------------------------------------------------
	jsl.DataSource.DataSet.prototype.__sort = function(r1, r2) {
		var ds, id, a, l

		r1 = r1.r
		r2 = r2.r
		ds = arguments.callee.data

		for(a = 0, l = ds.length; a < l; a++) {
			id = ds[a][0]
			if(r1[id] !== r2[id])
				break
		}

		if(a === l) 							return 0
		else if(r1[id] < r2[id])	return ds[a][1] ? +1 : -1
		else											return ds[a][1] ? -1 : +1
	}
	//-------------------------------------------------------------------------------
	jsl.DataSource.DataSet.prototype.__exp = function(exp, params) {
		var s, f, md, a, l

		s 	= "var "
		md	= this.__md

		for(a = 0, l = md.length; a < l; a++)
			s += md[a].id + "=row." + md[a].id + ","

		if(params) {

			s += " __ps = arguments.callee.__ps,"

			for(a = 0, l = params.length; a < l; a++) {
				if(!a) s += "$=__ps[" + a + "],"
				s += "$" + (a + 1) + "=__ps[" + a + "],"
			}
		}

		s = s.slice(0, -1) + ";return (" + exp + ")"

		try 			{ f = Function("row", s) }
		catch(e) 	{ throw jsl.ParamError("SyntaxError:filter", e) }

		f.__ps = params
		return f
	}
	//-------------------------------------------------------------------------------
  jsl.DataSource.DataSet.prototype.__clone  = jsl.Object.clone
  //-------------------------------------------------------------------------------
  jsl.DataSource.DataSet.prototype.__cloneR = function(row) {
    var md, nm, r

    md  = this.__md
    nm  = md.length
    r   = {}

    for(var a = 0; a < nm; a++)
      r[md[a].id] = row[md[a].id]

    return r
  }
